#include "operate-flash.h"

static uint32_t get_flash_addr(enum Start_flash_address_e start_addr_type)
{
	uint32_t Address;
	switch(start_addr_type)
	{
	case E_START_FLASH_ADDR_FCNT:
		Address = START_ADDR_FCNT;
		break;
	case E_START_FLASH_ADDR_JOIN_INFO:
		Address = START_ADDR_JOIN_INFO;
		break;
	case E_START_FLASH_ADDR_DEVICE_EUI:
		Address = START_ADDR_DEVICE_EUI;
		break;
	default:
		return 0;
//		break;
	}
	return Address;
}

/*!
 *\brief Read data from flash
 *\param[OUT] datas
 *\param[IN]  length Length of datas
 *\param[IN]  start_addr_type
 *\retval status [true: OK, false: ERROR]
 */
bool Read_flash_data(uint8_t datas[], uint8_t length, enum Start_flash_address_e start_addr_type)
{
	uint32_t Address = get_flash_addr(start_addr_type);
	if(0 == Address)
	{
		return false;
	}
	
	uint8_t word_cnt = (0 == length%4) ? length/4 : (length/4) + 1;
	
	uint32_t word_tmp;
	
	for(uint8_t i = 0; i < word_cnt; i++)
	{
		word_tmp = *(__IO uint32_t*)Address;
		datas[i*4] = word_tmp & 0xff;
		datas[i*4+1] = (word_tmp >> 8) & 0xff;
		datas[i*4+2] = (word_tmp >> 16) & 0xff;
		datas[i*4+3] = (word_tmp >> 24) & 0xff;
		Address = Address + 4;
	}
	return true;
}

/*!
 *\brief Write data to flash
 *\param[IN] datas    
 *\param[IN] length   Length of datas
 *\param[IN] start_addr_type    
 *\retval status [true: OK, false: ERROR]
 */
bool Write_flash_data(uint8_t datas[], uint8_t length, enum Start_flash_address_e start_addr_type)
{
	uint32_t Address = get_flash_addr(start_addr_type);
	if(0 == Address)
	{
		return false;
	}
	uint8_t word_cnt = (0 == length%4) ? length/4 : ((length/4)+1);
	uint32_t word_tmp;
	
    HAL_FLASH_Unlock();
	
	FLASH_EraseInitTypeDef EraseInitStruct;
    EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
    EraseInitStruct.PageAddress = Address;

    // Calculat a number of page to erase from start address
    EraseInitStruct.NbPages = (0 == length%128) ? length/128 : ((length/128)+1);
    
    if(EraseInitStruct.NbPages == 0)
        return false;

	uint32_t PageError = 0;
    if(HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK)
    {
		HAL_FLASH_Lock();
		return false;
	}	
		
	for(uint8_t i = 0; i < word_cnt; i++)
	{
		word_tmp = 0;
		word_tmp = ((datas[i*4]) | (datas[i*4+1] << 8) | (datas[i*4+2] << 16) | (datas[i*4+3] << 24));
		uint8_t status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, word_tmp);
		if(status != HAL_OK)
		{
            HAL_FLASH_Lock();
			return false;
		}	
		Address = Address + 4;
	}
	
	HAL_FLASH_Lock();
	return true;
}

